// WavFileTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include "SFML/Audio/SoundBuffer.hpp"
#include "../Vocoder/Vocoder.h"
#include "../Vocoder/CarrierImpl.h"
#include "../Vocoder/LoopCarrier.h"
#include "../Vocoder/ResynthCarrier.h"
#include "../Vocoder/OverlappingModulator.h"
#include "../Vocoder/OverlappingCarrier.h"
#include "../Vocoder/ModulatorImpl.h"
#include "../Vocoder/SoundBank.h"
#include "../Vocoder/PitchTracker.h"
#include "../Vocoder/PerformanceMonitor.h"
#include "../Vocoder/SequencedFrequencyProvider.h"
#include "../Vocoder/Overlapper.h"
#include "../Vocoder/RandomFrequencyProvider.h"
#include "../Vocoder/Scale.h"
#include "../Vocoder/FFTWrapper.h"
#include "../SAPIAdapter/SAPIController.h"
#include "../SFMLAdapter/Recorder.h"
//#include "OutputBuffer.h"
#include "VocoderDriver.h"
#include "SimpleIni.h"
#include "SAPIStreamReceiver.h"
#include "SAPIEventCb.h"

static CSimpleIniW* iniFile = NULL;

int ReadCarrierInt(const WCHAR* key, long defVal=0)
{
	return (int)iniFile->GetLongValue(L"carrier", key, defVal);
}

void ReadCarrierSettings(Settings::CarrierSettings* carrier)
{
	carrier->intensityVariation = ReadCarrierInt(L"intensity_variation");
	carrier->frequencyVariation = ReadCarrierInt(L"frequency_variation");
	carrier->random = ReadCarrierInt(L"random_wave", 200);
	carrier->square = ReadCarrierInt(L"square_wave", 200);
	carrier->sawtooth = ReadCarrierInt(L"sawtooth_wave", 200);
	carrier->sine = ReadCarrierInt(L"sine_wave", 200);
	carrier->triangular = ReadCarrierInt(L"triangular_wave", 200);
	carrier->modulator = ReadCarrierInt(L"modulator_intensity", 100);
	carrier->function1 = ReadCarrierInt(L"user_func1", 200);
	carrier->function2 = ReadCarrierInt(L"user_func2", 200);
	carrier->function3 = ReadCarrierInt(L"user_func3", 200);
	carrier->freq2 = ReadCarrierInt(L"freq2", 50);
	carrier->freq3 = ReadCarrierInt(L"freq3", 50);
	carrier->freq4 = ReadCarrierInt(L"freq4", 50);
	carrier->freq5 = ReadCarrierInt(L"freq5", 50);
	carrier->freq6 = ReadCarrierInt(L"freq6", 50);
	carrier->freq7 = ReadCarrierInt(L"freq7", 50);
	carrier->freq8 = ReadCarrierInt(L"freq8", 50);
	carrier->freq9 = ReadCarrierInt(L"freq9", 50);
}

int ReadVocoderInt(const WCHAR* key, long defVal=0)
{
	return (int)iniFile->GetLongValue(L"vocoder", key, defVal);
}

void ReadVocoderSettings(Settings* settings)
{
	settings->samplingRate = ReadVocoderInt(L"sampling_rate", 48000);
	settings->windowLength = ReadVocoderInt(L"window_length", 1024);
	settings->bandCount = ReadVocoderInt(L"band_count", 32);
	settings->overlapLength = ReadVocoderInt(L"overlap_length", settings->windowLength/2);
}

static int isSapiModulator = 0;
static std::wstring voiceName;
static std::wstring speech;
void ReadSettings(Settings* settings) 
{
	CSimpleIniW ini;
	iniFile = &ini;
	if(ini.LoadFile(L"vocoder.ini")<0)
	{
		return;//no ini file
	}	
	ReadVocoderSettings(settings);
	ReadCarrierSettings(settings->GetCarrier());

	isSapiModulator = (int)iniFile->GetLongValue(L"modulator", L"sapi_modulator");
	if(isSapiModulator)
	{
		voiceName = iniFile->GetValue(L"modulator", L"voice_name");
		speech = iniFile->GetValue(L"modulator", L"speech");
	}



	iniFile = NULL;
}

void createSequence(SequencedFrequencyProvider* seqProvider, int sampleLength)
{
	//for now, split the sample into 4 notes
	int part = sampleLength / 4;
	seqProvider->AddSequence(110, part);//A2
	seqProvider->AddSequence(131, part);//C3
	seqProvider->AddSequence(177, part);//F3
	seqProvider->AddSequence(165, part);//E3
}

void loadCarrier(LoopCarrier* carrier)
{
	const std::string filename("carrier.wav");
	//const std::string filename("modulator.wav");
	sf::SoundBuffer soundFile;
	soundFile.LoadFromFile(filename);
	int fileLen = soundFile.GetSamplesCount();
	short* sample = (short*)soundFile.GetSamples();
	carrier->SetSample(sample, fileLen);
}


static SAPIController sapiController;
static SAPIStreamReceiver sapiStreamReceiver;
static SAPIEventCb sapiEventCb;
int loadModulator(ModulatorImpl* modulator, char* fname, int sampleRate)
{
	int fileLen = 0;
	if(isSapiModulator)
	{
		::CoInitialize(NULL);
		sapiController.Initialize(&sapiEventCb, &sapiStreamReceiver, sampleRate, (WCHAR*)voiceName.c_str());
		sapiController.Speak((WCHAR*)speech.c_str(), false);
		while(!sapiEventCb.inputStreamDone)
		{
			Sleep(1);
		}
		fileLen = sapiStreamReceiver.samples.size();
		modulator->SetSample(&(sapiStreamReceiver.samples)[0], fileLen, NULL);
		sapiController.Destroy();
		::CoUninitialize();
	}
	else
	{
		const std::string filename(fname);
		sf::SoundBuffer soundFile;
		soundFile.LoadFromFile(filename);
		fileLen = soundFile.GetSamplesCount();
		short* sample = (short*)soundFile.GetSamples();
		modulator->SetSample(sample, fileLen);
	}
	return fileLen;
}

int _tmain(int argc, _TCHAR* argv[])
{
	//int WINDOW_LENGTH = 2048;
	//int WINDOW_LENGTH = 4096;
	//int WINDOW_LENGTH = 8192;
	Vocoder vocoder;
	ReadSettings(vocoder.GetSettings());
	int SAMPLE_RATE = vocoder.GetSettings()->samplingRate;//48000;
	int WINDOW_LENGTH = vocoder.GetSettings()->windowLength;//1024;
	int OVERLAP_LENGTH = vocoder.GetSettings()->overlapLength;

	PerformanceMonitor performance;
	//OutputBuffer output(&performance);
	Recorder recorder;

	PitchTracker pitchTracker(WINDOW_LENGTH, SAMPLE_RATE);
	SequencedFrequencyProvider seqProvider;
	RandomFrequencyProvider randProvider(220, 440, 10, 30);
	
	SoundBank soundBank(SAMPLE_RATE);
	Scale scale;
	//scale.SetChromatic();
	scale.SetAMinor();
	CarrierImpl carrier;
	//carrier.SetFrequencyProvider(&pitchTracker);
	//carrier.SetFrequencyProvider(&seqProvider);
	carrier.SetFrequencyProvider(&randProvider);
	carrier.SetVocoderListener(&recorder);
	carrier.soundBank = &soundBank;
	carrier.scale = &scale;

	LoopCarrier loopCarrier;
	loadCarrier(&loopCarrier);

	ResynthCarrier resynthCarrier(SAMPLE_RATE, &soundBank);	
	
	FFTHiPassProcessor fftHiPassProcessor(10);
	//resynthCarrier.fftProcessors.push_back(&fftHiPassProcessor);

	FFTLowPassProcessor fftLowPassProcessor(100);
	//resynthCarrier.fftProcessors.push_back(&fftLowPassProcessor);

	FFTBandPassProcessor fftBandProcessor(5, 100);
	//resynthCarrier.fftProcessors.push_back(&fftBandProcessor);

	FFTRandomSwapProcessor randomSwapProcessor;
	resynthCarrier.fftProcessors.push_back(&randomSwapProcessor);


	FFTShiftUpProcessor fftUpProcessor(10);
	//resynthCarrier.fftProcessors.push_back(&fftUpProcessor);

	FFTShiftDownProcessor fftDownProcessor(20);
	//resynthCarrier.fftProcessors.push_back(&fftDownProcessor);

	unsigned int bins[] = {5, 10, 15, 20, 25, 30};
	FFTBinMaximizer fftBinMaxProcessor(bins, 5);
	//resynthCarrier.fftProcessors.push_back(&fftBinMaxProcessor);

	FFTBinDampener fftBinDampenerProcessor(9);
	//resynthCarrier.fftProcessors.push_back(&fftBinDampenerProcessor);



	ModulatorImpl modulatorImpl;
	char* fname = NULL;
	if(argc==1)
		fname = "modulator.wav";
	else
		fname = (char*)argv[1];	
	int fileLen = loadModulator(&modulatorImpl, fname, SAMPLE_RATE);


	OverlappingModulator overlappingModulator(&modulatorImpl, OVERLAP_LENGTH);
	createSequence(&seqProvider, fileLen);

	//Carrier* theCarrier = &carrier;
	//Carrier* theCarrier = &loopCarrier;
	Carrier* theCarrier = &resynthCarrier;
	OverlappingCarrier overlappingCarrier(theCarrier, OVERLAP_LENGTH);
	theCarrier = &overlappingCarrier;

	//Modulator* theModulator = &modulatorImpl;
	Modulator* theModulator = &overlappingModulator;

	//vocoder.Initialize(&output, theCarrier, NULL, &recorder, NULL);
	Overlapper overlapper(OVERLAP_LENGTH);	
	vocoder.Initialize(theCarrier, NULL, &recorder, &overlapper);
	VocoderDriver driver;
	driver.Initialize(vocoder.GetSettings(), theModulator, theCarrier, &vocoder, WINDOW_LENGTH);
	driver.Start();
	/*
	Modulator modulator(&performance);
	if(argc==1)
	{
		const std::string filename("modulator.wav");
		createSequence(&seqProvider, modulator.GetSampleLength(filename));
		modulator.Vocode(&vocoder, filename, WINDOW_LENGTH);
	}
	else if(argc==2)
	{
		const std::string filename((char*)argv[1]);
		createSequence(&seqProvider, modulator.GetSampleLength(filename));
		modulator.Vocode(&vocoder, filename, WINDOW_LENGTH);
	}
	*/

	recorder.SaveToFiles();
	return 0;
}

